﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Snowdreamist.Collection.ProducerConsumer;
using Snowdreamist.Threading;

namespace Snowdreamist.Windows.Notification
{
    public class NotificationService : INotificationService
    {
        public NotificationService()
        {
        }

        public TimeSpan DefaultDuration { get; set; }

        public virtual void Notify(NotificationScope scope, NotificationType type, InteractiveType interType, object content)
        {
            this.Notify(scope, type, interType, content, this.DefaultDuration);
        }

        public virtual void Notify(NotificationScope scope, NotificationType notifyType, InteractiveType interType, object content, TimeSpan duration)
        {
            NotificationJob job = new NotificationJob()
            {
                Scope = scope,
                NotificationType = notifyType,
                InteractiveType = interType,
                Content = content,
                Duration = duration
            };

            this.PushNotificationJob(job);
        }

        public bool GetOrWaitNotification(NotificationScope scope, out NotificationJob job)
        {
            switch (scope)
            {
                case NotificationScope.System:
                    return this._systemJobQueue.Wait(out job);

                case NotificationScope.Application:
                    return this._applicationJobQueue.Wait(out job);

                default:
                case NotificationScope.Background:
                    return this._backgroundJobQueue.Wait(out job);
            }
        }

        public IEnumerable<NotificationJob> WaitNotifications(NotificationScope scope)
        {
            while (true)
            {
                NotificationJob job = null;
                if (this.GetOrWaitNotification(scope, out job))
                {
                    yield return job;
                }
                else
                {
                    break;
                }
            }
        }

        #region protected

        protected virtual void PushNotificationJob(NotificationJob job)
        {
            if (job == null)
                throw new ArgumentNullException("job");
            switch (job.Scope)
            {
                case NotificationScope.System:
                    this._systemJobQueue.Push(job);
                    break;

                case NotificationScope.Application:
                    this._applicationJobQueue.Push(job);
                    break;

                default:
                case NotificationScope.Background:
                    this._backgroundJobQueue.Push(job);
                    break;
            }
        }

        #endregion protected

        #region private

        // background
        private readonly ProConQueue<NotificationJob> _backgroundJobQueue = new ProConQueue<NotificationJob>();

        // application
        private readonly ProConQueue<NotificationJob> _applicationJobQueue = new ProConQueue<NotificationJob>();

        // system
        private readonly ProConQueue<NotificationJob> _systemJobQueue = new ProConQueue<NotificationJob>();

        // cancellation
        private readonly CancellationToken _cancellation = new CancellationToken();

        #endregion private
    }
}